﻿/*
Plugin=getDocumentPath
Name1=获取当前文件/程序的路径
Command1=DM_open_path
Param1={tc|TOTALCMD.EXE|TOTALCMD|资管|资源管理器|explorer|explorer.exe}
Author=yyy  Run修改
Version=1.0
注释：
在菜单编辑界面的命令框输入函数名称（不带括弧）即可调用函数，只是这样不会在内置命令列表里面显示
*/


/*
打开程序编辑文件所在位置

支持程序：
1、com 方式：Word、Excel、PowerPoint、SciTE
2、窗口标题方式：EverEdit、EmEditor、Sublime text、notepad2、notepad++ 等智能获取，灵感来自 Array
3、启动参数方式：帮助文档、压缩包、图片查看等

com 来自 sunwind，winmgmt 来自 Array

版本更新：
1.0 初版。
1.1 修正路径有2个空格及以上的问题。
1.2 改用新的提取路径方法。最终路径如果不存在为程序 exe 路径。
*/


DM_open_path(aParam){    ; 此Plugin执行的command为Test，代表执行Test函数,函数请预留一个aParam，用于QuickZ传递参数过来。
	icon:=A_ScriptDir . "\User\Icons\explorer.ico"
    open_path_Menu := MenuZ_GetSibling() ; 获取一个菜单对象，不是子菜单，是同级菜单
    ;~ open_path_Menu := MenuZ_GetSub() ; 获取一个子菜单对象，跟上面的不一样
    ;~ TestMenu.Add({name:"你好"，icon:"" }) ;   如果参数不是变量的话需要用引号引起来，中间的参数不能省略，可以给赋空值，像这儿的icon
    open_path_Menu.Add({name:"&G  左键TC打开 右键资管打开 中键打开程序exe的路径",icon: icon,uid:{Handle:"dm_open_path_Handle",Data:aParam}}) ; Handle的值为点击菜单后执行的功能
    return open_path_Menu  ; 必须返回子菜单对象
}


dm_open_path_Handle(aMsg, aObj)
{
	;~ if ( aMsg = "onselect" )           ;如果鼠标移动到菜单上显示提示信息，显示的时候一卡一卡的，体验不好，暂且关掉
	;~ {
    ;~ rect := aObj.GetRECT()
    ;~ CoordMode, ToolTip, Screen
    ;~ tooltip,% "左键资管打开 右键TC打开 中键打开程序exe的路径" ,% rect.right,% rect.top
	;~ sleep 300
	;~ ToolTip
	;~ }
	;Global gMenuZ
    If (aMsg = "OnRun")
	{
		tc_open_path()
	}
	else If (aMsg = "onmbutton")
	{
		explorer_open_exepath()	
		;gMenuZ.PUM.Destroy()
		;winclose,A
	}
	else If (aMsg = "OnRButton")
	{
		explorer_open_path()
		;gMenuZ.PUM.Destroy()
		;winclose,A
	}
}

explorer_open_exepath()
{
	Global gMenuZ
	iHwnd := gMenuZ.Data.Hwnd
	WinGet, pPath, Processpath, ahk_id %iHwnd%
	SplitPath,pPath,pName,pDir,,pNameNoExt
	Run % "explorer.exe /select," pPath
	sleep,200
	send,{esc}
}


open_path(aParam){     		;;TC打开文件/程序路径
	if (aParam="explorer") or (aParam="资管") or (aParam="资源管理器") or (aParam="explorer.exe") {
		explorer_open_path()
		return
	}
	else if (aParam="tc") or (aParam="TOTALCMD") or (aParam="TOTALCMD.EXE") 
		tc_open_path()
	else
		MsgBox 请在参数框输入tc、TOTALCMD、TOTALCMD.EXE则指定用tc打开路径 "`n" 输入explorer、资管、资源管理器、explorer.exe则指定用资源管理器打开路径
}

;QZData("%tc%")  可以这样来调用tc变量

tc_open_path(){	
	candysel:=QZData("Files")
	if (QZData("%TOTALCMD%")!="")		;如果变量TOTALCMD存在就用他的变量，如果不存在就用tc这个变量，这两个变量是人们常设的变量，其余的自己修改
		tc_path:=QZData("%TOTALCMD%") 
	else
		tc_path:=QZData("%tc%") 
	tc_open_path:=getDocumentPath()
	candysel=%candysel%  ;去掉首尾空格
	if !candysel			;没有选中文件
	{
		if WinActive("ahk_exe explorer.exe")		;如果当前活动窗口是资管，则用tc打开当前资管所在路径
		{
			tc_Dir := Explorer_GetPath()
			Run "%tc_path%" /T /O /A /R="%tc_Dir%"		;如果没选中，则用tc打开当前资管所在路径
		}
		else
			Run "%tc_path%" /T /O /A /R="%tc_open_path%"		;如果不是资管，则用tc打开程序/文件所在路径
		return
	}
	;~ else if RegExMatch(candysel, "^.:\\\.*")
	if RegExMatch(candysel,"i)\n")		;如果选中的为多文件，则用tc打开父目录，并选中这些文件
	{
		Clipboard:=candysel			;把选中 的文件置入剪切板，方便下面发送消息
		tc_Dir := Explorer_GetPath()
		Run "%tc_path%"  /O /T   /R="%tc_Dir%"
		WinWaitActive,ahk_class TTOTAL_CMD,,10
		Sleep 200
		PostMessage, 1075, 2033, 0, , AHK_CLASS TTOTAL_CMD   ; 从剪贴板导入并选中文件列表
		;~ sleep 200
		;~ PostMessage, 1075, 2400, 0, , AHK_CLASS TTOTAL_CMD   ;批量重命名，发送重命名消息
		;~ sleep 200
		;~ WinWaitActive,ahk_class TMultiRename,,10
		return
	}
	else
	{
		Run "%tc_path%" /T /O /A /R="%candysel%"
	}
	return
}



explorer_open_path(){   			;资管打开文件/程序路径
	candysel:=QZData("Files")
	candysel=%candysel%  ;去掉首尾空格
	if RegExMatch(candysel, "^.:\\\.*")
	{
		if FileExist(candysel)
		{
			if InStr(FileExist(candysel), "D")
				Run, % "explorer.exe /open,"candysel  ;以上这三种Run都能执行
			else
				Run, % "explorer.exe /select,"candysel
			return
		}
		Run % "explorer.exe /select," getDocumentPath()
		return
	}
	else
		Run % "explorer.exe /select," getDocumentPath()
	sleep,200
	send,{esc}
	return
}


Explorer_GetPath(hwnd="")
{
	if !(window := Explorer_GetWindow(hwnd))
		return ErrorLevel := "ERROR"
	if (window="desktop")
		return A_Desktop
	path := window.LocationURL
	path := RegExReplace(path, "ftp://.*@","ftp://")
	StringReplace, path, path, file:///
	StringReplace, path, path, /, \, All
	; thanks to polyethene
	loop
		if RegExMatch(path, "i)(?<=%)[\da-f]{1,2}", hex)
			StringReplace, path, path, `%%hex%, % Chr("0x" . hex), All
		else break
	return path
}


Explorer_GetWindow(hwnd="")
{
	; thanks to jethrow for some pointers here
	WinGet, Process, ProcessName, % "ahk_id" hwnd := hwnd? hwnd:WinExist("A")
	WinGetClass class, ahk_id %hwnd%

	if (Process!="explorer.exe")
		return
	if (class ~= "(Cabinet|Explore)WClass")
	{
		for window in ComObjCreate("Shell.Application").Windows
			if (window.hwnd==hwnd)
				return window
	}
	else if (class ~= "Progman|WorkerW")
		return "desktop" ; desktop found
}


class Asc extends Asc.Asc{
	class Asc{
		__Get(ByRef string){
static Ord:=("Asc",ObjRemove(Asc,"Asc"),"Ord")
InputString:=("string",string)
loop, Parse, %InputString%
	ascString.=(_:=%Ord%(A_LoopField))<0x100?"{ASC " _ "}":A_LoopField
return ascString
}
}
}

AscSend(str){    ;自定义函数—ZCS  发送愿意的字符串不受输入法影响
	SendInput % Asc[str]
}


; 返回程序编辑文件的路径
getDocumentPath()
{
	;~ Global QuickZ					;qz1版本中的变量
	;~ iHwnd := QuickZ.Hwnd
	Global gMenuZ
	iHwnd := gMenuZ.Data.Hwnd
	; WinGet, iHwnd, ID, A

	WinGet, pPath, Processpath, ahk_id %iHwnd%
	SplitPath,pPath,pName,pDir,,pNameNoExt

	;~ ; 按住 ctrl 返回程序路径
	;~ KeyState := GetKeyState2("lwin")
	;~ if keyState = D
	;~ {
		;~ MsgBox % pPath
		;~ return pPath
	;~ }

	if IsLabel("Case_" pNameNoExt)
		goto Case_%pNameNoExt%
	else
		goto Case_Default

Case_WINWORD:  ;Word
	app:= ComObjActive("Word.Application")
	doc:= app.ActiveDocument
return % doc.FullName

Case_EXCEL:  ;Excel
	app := ComObjActive("Excel.Application")
	cBook := app.ActiveWorkbook
return % cBook.FullName

Case_POWERPNT:  ;PowerPoint
	app := ComObjActive("Powerpoint.Application")
	activePresentation := App.ActivePresentation
return % activePresentation.FullName

Case_SciTE:  ; 打开SciTE当前文件所在目录
return % GDP_GetCurrentFilePath(GDP_GetSciTEInstance())

Case_Default:
	; 从标题中获取可能的路径
	WinGetTitle, winTitle, ahk_id %iHwnd%
	dPath := getDocumentPathFromStr(winTitle)

	if (!dPath) {
		; 从启动命令行获取可能的路径
		WinGet, NumPID, PID, ahk_id %iHwnd%
		CommandLine := winmgmt("CommandLine", "Where ProcessId = " NumPID "")
		StringReplace, dPath, CommandLine, %pPath%,, All
		;dPath := RegExReplace(CommandLine, ToMatch(pPath))
		dPath := getDocumentPathFromStr(dPath)
	}

	if (!dPath)
		dPath := pPath
return dPath
}

GDP_GetCurrentFilePath(scite)
{
	if !scite
	{
		MsgBox, 16, Error, Can't find SciTE!
		ExitApp
	}
	return scite.CurrentFile
}

GDP_GetSciTEInstance()
{
	olderr := ComObjError()
	ComObjError(false)
	scite := ComObjActive("SciTE4AHK.Application")
	ComObjError(olderr)
	return IsObject(scite) ? scite : ""
}

winmgmt(v,w:="",d:="Win32_Process",m:="winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2"){
	s:=[]
	for i in ComObjGet(m).ExecQuery("Select " (v?v:"*") " from " d  (w ? " " w :""))
		s.Insert(i[v])
	return s.MaxIndex()?(s.MaxIndex()=1?s.1:s):""
}

;; 外部测试用
;GDP_test()
;GDP_test()
;{
;    sPaths =
;    (
;    c:\Program Files\Windows Mail aaaa
;    "" "c:\Program Files\Windows Mail\wab.exe"
;    c:\Program Files\Windows Mail\wab.exe - EverEdit
;    )

;    for i, v in StrSplit(sPaths, "`n")
;    {
;        MsgBox % getDocumentPathFromStr(v)
;    }
;}

getDocumentPathFromStr(strPath)
{
	; 提取可能的文件路径
	;RegExMatch(strPath, "(\w:\\.*\.[\w-]+)", s)  原版
	RegExMatch(strPath, "(\w:\\.*?\.[\w-]+)", s)  ;修改版
	if GDP_FileExist(s)
		return s

	; 按空格分割
	arr := StrSplit(strPath, A_Space)

	; 识别路径的开始和后面部分
	dPath =
	afterArr := []
	for i, v in arr
	{
		v := GDP_trimPath(v)
		if GDP_likePath(v)
		{
			dPath := GDP_trimPath(v)
			if GDP_FileExist(dPath)
				return dPath
		} else if (dPath) {
			afterArr.Insert(v)
		}
	}

	; 连接后面部分，查看是否存在
	for i, v in afterArr
	{
		dPath := dPath " " v
		dPath := GDP_trimPath(dPath)
		if GDP_FileExist(dPath)
			return dPath
	}
}

GDP_trimPath(s)  ; 去除前后干扰符
{
	;return Trim(s, " `t`")
	return Trim(s, " `t`n""")
}

GDP_FileExist(s)  ; 需要绝对路径
{
	return s && InStr(s, "\") && FileExist(s)
}

GDP_likePath(s)
{
	return RegExMatch(s, "\w:\\.*")
}